package com.liuqi.business.service.impl;


import com.liuqi.base.BaseMapper;
import com.liuqi.base.BaseServiceImpl;
import com.liuqi.business.enums.UsingEnum;
import com.liuqi.business.enums.WalletLogTypeEnum;
import com.liuqi.business.mapper.UserWalletMapper;
import com.liuqi.business.model.CurrencyModel;
import com.liuqi.business.model.CurrencyModelDto;
import com.liuqi.business.model.UserWalletModel;
import com.liuqi.business.model.UserWalletModelDto;
import com.liuqi.business.service.*;
import com.liuqi.exception.BusinessException;
import com.liuqi.utils.MathUtil;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Service
@Transactional(readOnly = true)
public class UserWalletServiceImpl extends BaseServiceImpl<UserWalletModel, UserWalletModelDto> implements UserWalletService {

    @Autowired
    private UserWalletMapper userWalletMapper;

    @Override
    public BaseMapper<UserWalletModel, UserWalletModelDto> getBaseMapper() {
        return this.userWalletMapper;
    }

    @Autowired
    private CurrencyService currencyService;
    @Autowired
    private UserWalletUpdateLogService userWalletUpdateLogService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserWalletLogService userWalletLogService;

    /**
     * 修改
     *
     * @param t
     */
    @Override
    @Transactional
    public boolean update(UserWalletModel t) {
        cleanAllCache();
        cleanCacheByModel(t);
        //检查是否满足
        check(t);
        t.setUpdateTime(new Date());
        boolean status = this.getBaseMapper().update(t) > 0;
        if (status) {
            this.afterUpdateOperate(t);
            return status;
        } else {
            throw new BusinessException(t.getClass().getName() + "-id:" + t.getId() + "更新失败");
        }
    }


    /**
     * 查询用户钱包信息
     *
     * @param userId
     * @param currencyId
     * @return
     */
    @Override
    public UserWalletModelDto getByUserAndCurrencyId(Long userId, Long currencyId) {
        UserWalletModelDto wallet = userWalletMapper.getByUserAndCurrencyId(userId, currencyId);
        //插入时判断  如果没有钱包新建一个
        if (wallet == null) {
            wallet = ((UserWalletService) AopContext.currentProxy()).addWallet(userId, currencyId);
        }
        return wallet;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public UserWalletModelDto addWallet(Long userId, Long currencyId) {
        if (userId != null && currencyId != null && userId > 0 && currencyId > 0) {
            UserWalletModelDto wallet = new UserWalletModelDto();
            wallet.setUserId(userId);
            wallet.setFreeze(BigDecimal.ZERO);
            wallet.setUsing(BigDecimal.ZERO);
            wallet.setCurrencyId(currencyId);
            this.insert(wallet);
            return wallet;
        }
        return null;
    }

    @Override
    public List<UserWalletModelDto> getByUserId(Long userId, String currencyName) {
        UserWalletModelDto search = new UserWalletModelDto();
        search.setUserId(userId);
        List<Long> currencyList = null;
        currencyList = currencyService.getLikeByName(currencyName, UsingEnum.USING.getCode());
        if (currencyList == null || currencyList.size() == 0) {
            currencyList.add(-1L);
        }
        search.setCurrencyList(currencyList);
        return this.queryListByDto(search, true);
    }

    @Transactional
    @Override
    public void insertUserWallet(Long userId) {
        //初始化用户钱包
        List<CurrencyModelDto> curList = currencyService.getUsing();
        for (CurrencyModel c : curList) {
            //获取钱包  没有时创建
            this.getByUserAndCurrencyId(userId, c.getId());
        }
    }

    @Override
    @Transactional
    public void adminUpdate(UserWalletModelDto wallet, Long opeId) {
        //获取原对象
        UserWalletModelDto model = this.getById(wallet.getId());
        BigDecimal oldUsing = model.getUsing();
        BigDecimal oldFreeze = model.getFreeze();
        BigDecimal modifyUsing = wallet.getUsing();
        BigDecimal modifyFreeze = wallet.getFreeze();
        BigDecimal newUsing = MathUtil.add(oldUsing, modifyUsing);
        BigDecimal newFreeze = MathUtil.add(oldFreeze, modifyFreeze);
        model.setUsing(newUsing);
        model.setFreeze(newFreeze);
        model.setUpdateTime(new Date());
        //更新数据
        this.modifyWallet(model.getUserId(), model.getCurrencyId(), modifyUsing, modifyFreeze);
        userWalletUpdateLogService.insert(oldUsing, modifyUsing, newUsing, oldFreeze, modifyFreeze, newFreeze, opeId, model.getUserId(), model.getCurrencyId(), wallet.getRemark());
        userWalletLogService.addLog(model.getUserId(), model.getCurrencyId(), modifyUsing, WalletLogTypeEnum.SYS.getCode(), 0L, "系统修改", wallet);

    }

    private void check(UserWalletModel wallet) {
        if (wallet.getUsing().compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException("u:" + wallet.getUserId() + ",c:" + wallet.getCurrencyId() + "，可用小于0->" + wallet.getUsing());
        }
        if (wallet.getFreeze().compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException("u:" + wallet.getUserId() + ",c:" + wallet.getCurrencyId() + "，冻结小于0->" + wallet.getFreeze());
        }
    }

    @Override
    protected void doMode(UserWalletModelDto dto) {
        super.doMode(dto);
        dto.setUserName(userService.getNameById(dto.getUserId()));
        dto.setRealName(userService.getRealNameById(dto.getUserId()));
        dto.setCurrencyName(currencyService.getNameById(dto.getCurrencyId()));
        dto.setPosition(currencyService.getPositionById(dto.getCurrencyId()));
    }


    @Override
    @Transactional
    public UserWalletModelDto modifyWallet(Long userId, Long currencyId, BigDecimal changeUsing, BigDecimal changeFreeze) {
        if (userId != null && currencyId != null && userId > 0 && currencyId > 0) {
            UserWalletModelDto dto = this.getByUserAndCurrencyId(userId, currencyId);
            boolean status = userWalletMapper.modifyWallet(userId, currencyId, changeUsing, changeFreeze) > 0;
            if (status) {
                dto = this.getByUserAndCurrencyId(userId, currencyId);
            } else {
                System.out.println("u:" + userId + ",c:" + currencyId);
                throw new BusinessException("余额不足");
            }
            return dto;
        }
        throw new BusinessException("参数异常u:" + userId + ",c:" + currencyId);
    }

    @Override
    @Transactional
    public UserWalletModelDto modifyWalletUsing(Long userId, Long currencyId, BigDecimal changeUsing) {
        if (userId != null && currencyId != null && userId > 0 && currencyId > 0) {
            UserWalletModelDto dto = this.getByUserAndCurrencyId(userId, currencyId);
            boolean status = userWalletMapper.modifyWalletUsing(userId, currencyId, changeUsing) > 0;
            if (status) {
                dto = this.getByUserAndCurrencyId(userId, currencyId);
            } else {
                System.out.println("u:" + userId + ",c:" + currencyId);
                throw new BusinessException("可用余额不足");
            }
            return dto;
        }
        throw new BusinessException("参数异常u:" + userId + ",c:" + currencyId);
    }

    @Override
    @Transactional
    public UserWalletModelDto modifyWalletFreeze(Long userId, Long currencyId, BigDecimal changeFreeze) {
        if (userId != null && currencyId != null && userId > 0 && currencyId > 0) {
            UserWalletModelDto dto = this.getByUserAndCurrencyId(userId, currencyId);
            boolean status = userWalletMapper.modifyWalletFreeze(userId, currencyId, changeFreeze) > 0;
            if (status) {
                dto = this.getByUserAndCurrencyId(userId, currencyId);
            } else {
                System.out.println("u:" + userId + ",c:" + currencyId);
                throw new BusinessException("冻结余额不足");
            }
            return dto;
        }
        throw new BusinessException("参数异常u:" + userId + ",c:" + currencyId);
    }

}
